<!DOCTYPE html>
<html lang="ch">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body onload="main()">
  <canvas id="glcanvas" width="640" height="480">
    你的浏览器似乎不支持或者禁用了HTML5 <code>&lt;canvas&gt;</code> 元素.
  </canvas>

  <script src="./static/js/gl-matrix-min.js"></script>
  <script>
    /**
     * 1.初始化WebGL上下文
     * 2.初始化着色器
     * 3.创建一个缓冲器来存储它的顶点
     * 4.渲染场景
    */

    // 初始化 mat4
    var mat4 = glMatrix.mat4;

    // 设置 WebGL 上下文并开始渲染内容
    function main() {
      var canvas = document.getElementById('glcanvas')
      // 用create能智能提示api
      // var canvas = document.createElement('canvas')
      // 初始化WebGL上下文
      var gl = canvas.getContext("webgl")

      if (!gl) {
        alert('不支持webgl')
        return;
      }

      // 顶点着色器
      const vsSource = `
    attribute vec4 aVertexPosition;

    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;

    void main() {
      gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
    }
  `;

      // 片段着色器
      const fsSource = `
    void main() {
      gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }
  `;

      const shaderProgram = initShaderProgram(gl, vsSource, fsSource)

      const programInfo = {
        program: shaderProgram,
        attribLocations: {
          vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
        },
        uniformLocations: {
          projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
          modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
        },
      };

      var buffers = initBuffers(gl)
      drawScene(gl, programInfo, buffers)

    }

    // 初始化着色器
    function initShaderProgram(gl, vsSource, fsSource) {
      const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource)

      const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);

      // 创建着色器程序
      const shaderProgram = gl.createProgram()
      gl.attachShader(shaderProgram, vertexShader)
      gl.attachShader(shaderProgram, fragmentShader)
      gl.linkProgram(shaderProgram)

      // 检测
      if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
        alert('初始化着色器失败')
        return null
      }
      return shaderProgram;
    }

    // 创建指定类型的着色器，上传source源码并编译
    function loadShader(gl, type, source) {
      const shader = gl.createShader(type)
      // 将源代码发送到着色器
      gl.shaderSource(shader, source)
      // 着色器编译。
      gl.compileShader(shader)

      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert('初始化着色器失败')
        // 删除着色器返回null，表明加载着色器失败。
        gl.deleteShader(shader);
        return null
      }
      return shader
    }


    // 创建一个缓冲器来存储它的顶点
    function initBuffers(gl) {
      // 获取缓冲区对象
      const positionBuffer = gl.createBuffer()
      // 绑定上下文
      gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)

      var vertices = [
        1.0, 1.0, 0.0,
        -1.0, 1.0, 0.0,
        1.0, -1.0, 0.0,
        -1.0, -1.0, 0.0
      ]

      // 建立对象的顶点
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)

      return {
        position: positionBuffer
      }
    }

    // 渲染场景
    function drawScene(gl, programInfo, buffers) {
      // 使用完全不透明的黑色清除所有图像
      gl.clearColor(0.0, 0.0, 0.0, 1.0);
      // 用背景色插除画布
      gl.clearDepth(1.0)
      gl.enable(gl.DEPTH_TEST)
      gl.depthFunc(gl.LEQUAL)

      // 开始画画之前用上面指定的颜色把画布清理干净。  
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)


      const fieldOfView = 45 * Math.PI / 180
      // 设置一个适合实际图像的宽高比
      const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight
      // 指定在摄像机距离0.1到100单位长度的范围内的物体可见。
      const zNear = 0.1
      const zFar = 100.0
      const projectionMatrix = mat4.create()

      //创建一个透视矩阵，一个特殊的矩阵  
      mat4.perspective(projectionMatrix,
        fieldOfView,
        aspect,
        zNear,
        zFar
      )

      // 将绘图位置设置为“标识”点
      //场景的中心。  
      const modelViewMatrix = mat4.create()

      // 加载特定位置，并把正方形放在距离摄像机6个单位的的位置。然后，我们绑定正方形的顶点缓冲到上下文，并配置好，再通过调用 drawArrays() 方法来画出对象 
      //开始画正方形。  
      mat4.translate(modelViewMatrix,  //目的地矩阵
        modelViewMatrix, // 翻转矩阵
        [-0.0, 0.0, -6.0] // 翻转量
      )

      //告诉WebGL如何从位置拉出位置  
      // buffer到vertexPosition属性。  
      {
        const numComponents = 3   //每次迭代提取3个值
        const type = gl.FLOAT     // buffer 类型是32bit float
        const normalize = false   // 不使用标准化
        const stride = 0           //从一组值到下一组值需要多少字节
        const offset = 0           //从缓冲区内多少字节开始  

        gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position)
        gl.vertexAttribPointer(
          programInfo.attribLocations.vertexPosition,
          numComponents,
          type,
          normalize,
          stride,
          offset
        )
        gl.enableVertexAttribArray(
          programInfo.attribLocations.vertexPosition
        )
      }

      // 告诉WebGL在绘图时使用我们的程序
      gl.useProgram(programInfo.program)

      // 设置着色器uniforms
      gl.uniformMatrix4fv(
        programInfo.uniformLocations.projectionMatrix,
        false,
        projectionMatrix
      )
      gl.uniformMatrix4fv(
        programInfo.uniformLocations.modelViewMatrix,
        false,
        modelViewMatrix
      )
      {
        const offset = 0
        const vertexCount = 4
        // 画出对象
        gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount)
      }
    }
  </script>
</body>

</html>